/*
@功能：基于ESP8266的天气时钟
@时间：2020/3/13
@作者：刘泽文
@QQ：2822604962
*/
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <math.h>
#include <FastLED.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <U8g2lib.h>
#include "weather.h"
#include <DS3231.h>
#include <Wire.h>

//引入字体
#include"font.h"

//注册RGB灯数目类
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
CRGB* const leds( leds_plus_safety_pixel + 1);

//视频播放服务器地址
const char* badapple_Server = "192.168.31.45";//你的电脑IP，win+R后，输入ipconfig查看
const int badapple_Port = 715;//上位机中默认端口

short badapple_Status = 0;
uint8_t badapple[1024]={}; //128 * 64 / 8 = 1024

//显示器定时关闭定时器
Ticker openDisplay;

//DS3231初始化
DS3231 Clock;
bool Century=false;
bool h12;
bool PM;

//网络时钟定义
static const char ntpServerName[] = "time1.aliyun.com";//NTP服务器
const int timeZone = 8;     //时区
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP 端口
time_t prevDisplay = 0; // when the digital clock was displayed

//构造u8g2显示器
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

//天气WiFiClient
WiFiClient client;
//哔哩哔哩HTTPClient
HTTPClient bilibili_client1;
HTTPClient bilibili_client2;
//badapple的WiFiClient
WiFiClient badapple_client;

void offDisplay();//关屏幕回调函数
uint8_t KEY_Scan(uint8_t mode);//按键扫描函数1
uint8_t KEY_Scan2(void);//按键扫描函数2
char *num_week(uint8_t dayofweek,int Mode);//计算星期
void page_int(char * name,uint8_t cur,uint8_t row,long time);//初始化所有页码
void gpio_int(void);//初始化IO口
void city_int(void);//初始化城市结构体数组
void OLED_int(void);//初始化0.96OLED
void bilibili_int(void);//初始化bilibili请求
void bilibili_http_get(void);//从http更新哔哩哔哩数据
void get_time(void);//获取时间到TIME_NOW,由TIME_MODE决定是DS3231时间还是NTP网络时间
void Desktop1(void);//桌面1(天气时钟)
void Desktop2(void);//桌面2(bilibili粉丝数)
void set_page(void);//设置界面
void update_time(void);//更新NTP时间到DS3231
bool autoConfig(void);//自动联网
void smartConfig(void);//smartConfig智能配网
bool sendRequest(const char* host, const char* cityid, const char* apiKey); //发送连接
bool skipResponseHeaders(void); 
void readReponseContent(char* content, size_t maxSize); 
void stopConnect(void);//停止请求
void clrEsp8266ResponseBuffer(void);//清理缓存
bool parseUserData(char* content);//拷贝信息进userDatd内
void classified_weather(void);//对天气按照天气图标进行分类
void drawWeather(void);//画天气图标
void HariChord(int frame);//几何动画
void boot_animation(void);//开机动画
void print_firmware_information(void);//打印系统参数，固件版本信息
void BasicOTAINT(void);//OTA无线升级初始化
void WS2812_INT(void);//WS2812 RGB点阵初始化
uint16_t RGBXY( uint8_t x, uint8_t y);//WS2812 RGB点阵屏XY转地址函数（XY->i)  使用时可直接调用下面的RGBXYsafe
uint16_t RGBXYsafe( uint8_t x, uint8_t y);//WS2812 RGB点阵屏XY 判断输入XY是否超出最大值 超出返回-1 此时设置点阵不显示
void RGB_ShowChar(uint8_t x,uint8_t y,uint8_t chr);//RGB写字符函数
void RGB_ShowString(uint8_t x,uint8_t y,const char *chr);//RGB显示字符串
void RGB_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len);//RGB显示数字
void FONT_16_2(const unsigned char chr,int *point);//十六进制转数组
int RGB_POW(char m,char n);//RGB  m^n 
time_t getNtpTime(void);
void sendNTPpacket(IPAddress &address);

void setup(){
  Serial.begin(BAUD_RATE);//串口初始化
  print_firmware_information();//打印版本信息

  gpio_int();//初始化IO口
  city_int();//初始化城市列表
  OLED_int();//初始化0.96OLED
  WS2812_INT();//WS2812 RGB点阵初始化
  delay(100);
  boot_animation();//开机动画
  ESP.wdtEnable(5000);//看门狗初始化
  //配置网络
  WiFi.disconnect();
  strcpy(config.stassid, ssid);   
  strcpy(config.stapsw, pswd); 
  if(WiFi.status() != WL_CONNECTED){
    WIFI_MODE = 0;
    if(autoConfig())
      WIFI_MODE = 1;
    else{
      WIFI_MODE = 0;
      TIME_MODE = 0;//无网络自动切换到DS3231时钟源
    }
  }
   DebugPrint("IP address: ");
   DebugPrintln(WiFi.localIP());
   DebugPrint("\n");

   BasicOTAINT();//OTA无线升级初始化
  
   //NTP网络时钟就绪
   Udp.begin(localPort);
   setSyncProvider(getNtpTime);
   setSyncInterval(300);

   Wire.begin();//初始化IIC总线

   bilibili_int();//初始化bilibili请求
   
   //初始各标志位时间
   LastWeatherTime = millis();//天气获取
   LastRtcTime = millis();//时间刷新
   
   DATA_UPDATA = 1;
   LED_OFF;//关灯
   DebugPrintln("*********************************初始化结束，进入loop函数！***********************************");
}

void loop(){
  if(WIFI_MODE){
    //检测client客户端是否连接
    while (!client.connected()){
    if (!client.connect(host, 80)){  
      LED_PWM;//闪灯
      delay(300);          
      ESP.wdtFeed();// 喂 狗      
      } 
    }
   
    //获取天气
    if(millis()-LastWeatherTime >= WeatherDelay||DATA_UPDATA){
      DATA_UPDATA = 0;
      if(RGB_KEY==1)
        RGB_ShowString(0,0,"Get!!");
      u8g2.clearBuffer();
      u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
      u8g2.setCursor(16, 36);
      u8g2.print("更新信息中......"); 
      u8g2.sendBuffer();
      LastWeatherTime = millis();
      LED_ON;
      delay(100);
      LED_OFF;
      if(Desktop_Mode == TIME_WEATHER){
        if(sendRequest(host, citys[which_city-1].city_id, APIKEY) && skipResponseHeaders()){
          clrEsp8266ResponseBuffer();
          readReponseContent(response, sizeof(response));
          parseUserData(response);//拷贝需要的信息进userData
          classified_weather();
        }  
      }
      else if(Desktop_Mode == BILIBILI){
        bilibili_http_get();//请求哔哩哔哩数据
      }
    }

  }
        
 //获取本地时间并显示
  if(millis()-LastRtcTime >= RtcDelay){
    LastRtcTime = millis();
    get_time();
    Battery_capacity = analogRead(ADC_PIN);//获取电量
    switch (Desktop_Mode)
    {
      case TIME_WEATHER:
        Desktop1();
      break;
      case BILIBILI:
        Desktop2();
      break;
      default:
      break;
    }
  }

  uint8_t KEY=KEY_Scan2();//扫描按键
  switch(KEY){
    case NO_KEY_PRES:
      //无按键按下，直接跳出，加快运行时间
    break;
    case UP_KEY_PRES:
    DebugPrintln("*************TIME_MODE切换***************");
    if(TIME_MODE == DS3231_TIME_MODE)
      TIME_MODE = NTP_TIME_MODE;
    else
      TIME_MODE = DS3231_TIME_MODE;
    break;
    case M_KEY_PRES:
      u8g2.setPowerSave(LOW);
      openDisplay.once_ms(openOledTime, offDisplay);//定时器初始化
    break;
    case DOWN_KEY_PRES:
      //判断是否需要获取网络时间更新到DS3231上
      if(WIFI_MODE)
      update_time();
    break;
    case WAKE_UP_PRES:
      u8g2.setPowerSave(LOW);
      openDisplay.once_ms(openOledTime, offDisplay);//定时器初始化
    break;
    case M_KEY_LONG_PRES:
      set_page();
    break;
    case WAKE_UP_LONG_PRES:
      set_page();
    break;
  }

 //判断是否需要智能配网
 if(Get_SmartConfig)
  smartConfig();
  
  ArduinoOTA.handle();//OTA无线升级
  LED_OFF;//灭灯
  ESP.wdtFeed();// 喂 狗
}

/*
@功能:定时关闭显示屏回调函数
*/
void offDisplay(){
  DebugPrintln("************5s后关闭OLED***************");
  u8g2.setPowerSave(HIGH);//关屏幕
}

/*
@功能:获取时间
@参数：0：DS3231_TIME_MODE
       1:NTP_TIME_MODE
*/
void get_time(void){
  if(TIME_MODE){
    prevDisplay = now();
    TIME_NOW.years = year();
    TIME_NOW.months = month();
    TIME_NOW.days = day();
    TIME_NOW.hours = hour();
    TIME_NOW.minutes = minute();
    TIME_NOW.seconds = second();
    TIME_NOW.weeks = weekday();
  }else{
    TIME_NOW.years = Clock.getYear()+2000;
    TIME_NOW.months = Clock.getMonth(Century);
    TIME_NOW.days = Clock.getDate();
    TIME_NOW.hours = Clock.getHour(h12, PM);
    TIME_NOW.minutes = Clock.getMinute();
    TIME_NOW.seconds = Clock.getSecond();
    TIME_NOW.weeks = Clock.getDoW();
  }
}

/*
@功能:按键处理函数1
@参数：mode
       0：不支持连按
       1：支持连按
@返回值：0：无按键按下
*/
uint8_t KEY_Scan(uint8_t mode){   
  uint8_t key_up=1;//按键按松开标志
  if(mode)key_up=1;  //支持连按     
  if(key_up&&(KEYU==0||KEYM==0||KEYD==0||KEYW==0))
  {
    delay(4);//去抖动
    key_up=0;
    if(KEYU==0)return 1;
    else if(KEYM==0)return 2;
    else if(KEYD==0)return 3;
    else if(KEYW==0)return 4;
  }else if(KEYU==1||KEYM==1||KEYD==1||KEYW==1)key_up=1;
  return 0;// 无按键按下
}

/*
@功能:按键处理函数2
@返回值：短按||长按 下某个按键
*/
uint8_t KEY_Scan2(void){
  uint8_t KEY = KEY_Scan(0);
  switch(KEY)
  {
  case UP_KEY_PRES:
      up_pres_time = millis();
    break;
  case M_KEY_PRES:
      m_pres_time = millis();
    break;
  case DOWN_KEY_PRES:
      down_pres_time = millis();
    break;
  case WAKE_UP_PRES:
      wake_pres_time = millis();
  break;
  }
  while(KEYU==0||KEYM==0||KEYD==0||KEYW==0)
  {
    if(up_pres_time!=0 && millis()-up_pres_time >= key_long_pres_time){
      KEY = UP_KEY_LONG_PRES;
      break;
    }
    else if(m_pres_time!=0 && millis()-m_pres_time >= key_long_pres_time){
      KEY = M_KEY_LONG_PRES;
      break;
    }
    else if(down_pres_time!=0 && millis()-down_pres_time >= key_long_pres_time){
      KEY = DOWN_KEY_LONG_PRES;
      break;
    }
    else if(wake_pres_time!=0 && millis()-wake_pres_time >= key_long_pres_time){
      KEY = WAKE_UP_LONG_PRES;
      break;
    }
    ESP.wdtFeed();// 喂 狗   
  }
  up_pres_time = 0;
  m_pres_time = 0;
  down_pres_time = 0;
  wake_pres_time = 0;
  
  return KEY;
}

/*
@功能:判断星期并赋值
*/
char week1[10],week2[8],week3[2],week4[4];
char *num_week(uint8_t dayofweek,int Mode){
  switch(dayofweek)
  {
    case 1: 
    strcpy(week1,"Sunday");
    strcpy(week2,"周日");
    strcpy(week3,"Su");
    strcpy(week4,"日"); 
      break;
    case 2: 
    strcpy(week1,"Monday");
    strcpy(week2,"周一");
    strcpy(week3,"Mo");
    strcpy(week4,"一"); 
      break;
    case 3: 
    strcpy(week1,"Tuesday");
    strcpy(week2,"周二");
    strcpy(week3,"Tu");
    strcpy(week4,"二"); 
      break;
    case 4: 
    strcpy(week1,"Wednesday");
    strcpy(week2,"周三"); 
    strcpy(week3,"We");
    strcpy(week4,"三"); 
      break;
    case 5: 
    strcpy(week1,"Thursday");
    strcpy(week2,"周四"); 
    strcpy(week3,"Th");
    strcpy(week4,"四"); 
      break;
    case 6: 
    strcpy(week1,"Friday");
    strcpy(week2,"周五");
    strcpy(week3,"Fr"); 
    strcpy(week4,"五");
      break;
    case 7: 
    strcpy(week1,"Saturday");
    strcpy(week2,"周六"); 
    strcpy(week3,"Sa");
    strcpy(week4,"六");
      break;
    default:
    strcpy(week1,"NO");
    strcpy(week2,"无");
    strcpy(week3,"NO");
    strcpy(week4,"无");
      break; 
  }
  switch(Mode)
  {
    case 1: return week1; break;
    case 2: return week2; break;
    case 3: return week3; break;
    case 4: return week4; break;
  }
}

/*
@功能:初始化翻页参数
*/
void page_int(char * name,uint8_t cur,uint8_t row,long time){
  strcpy(set_up_page.name,name);
  set_up_page.cursor = cur;
  set_up_page.rows = row;
  set_up_page.time = time;
}

/*
@功能:初始化IO口
*/
void gpio_int(void){
  pinMode(LED,OUTPUT);
  pinMode(WAKE_UP,INPUT_PULLUP);
  pinMode(UP_KEY,INPUT_PULLUP);
  pinMode(M_KEY,INPUT_PULLUP);
  pinMode(DOWN_KEY,INPUT_PULLUP);
  LED_OFF;//关灯
}

/*
@功能:初始化城市结构体数组
*/
void city_int(void){
  strcpy(citys[0].city_name,"西安");strcpy(citys[0].city_id,"xian");
  strcpy(citys[1].city_name,"渭南");strcpy(citys[1].city_id,"weinan");
  strcpy(citys[2].city_name,"深圳");strcpy(citys[2].city_id,"shenzhen");
  strcpy(citys[3].city_name,"广州");strcpy(citys[3].city_id,"guangzhou");
}

/*
@功能:初始化0.96OLED
*/
void OLED_int(void){
  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setDisplayRotation(U8G2_R0);//设置显示器方向
  U8G2_OLED_R = 0;//OLED方向标志位置0（水平）
  u8g2.setContrast(OLED_Brightness);//设置OLED亮度
  u8g2.setDrawColor(1);//设置绘制颜色
  u8g2.setPowerSave(LOW);//默认屏幕亮
}

/*
@功能:初始化bilibili请求
*/
void bilibili_int(void){
   //设置超时
   bilibili_client1.setTimeout(HTTP_TIMEOUT);
   bilibili_client2.setTimeout(HTTP_TIMEOUT);
   //设置哔哩哔哩请求url:http://api.bilibili.com/x/space/upstat?mid=277392717
   bilibili_client1.begin(String(bilibili_HOST) + "/x/space/upstat?mid=" + String(bilibili_UID));//粉丝数
   bilibili_client2.begin(String(bilibili_HOST) + "/x/relation/stat?vmid=" + String(bilibili_UID));//播放量
}

/*
@功能:从http更新哔哩哔哩数据
*/
void bilibili_http_get(void){
  StaticJsonBuffer<1024> jsonBuffer;
  int httpCode1 = bilibili_client1.GET();
  if(httpCode1 > 0 && httpCode1==HTTP_CODE_OK)
  {
    String response = bilibili_client1.getString();
    DebugPrintln(response);
    JsonObject& root = jsonBuffer.parseObject(response);
    BILI_NOW_DATE.view = root["data"]["archive"]["view"];
    BILI_NOW_DATE.likes = root["data"]["likes"];
  }
  bilibili_client1.end();

  delay(100);

  int httpCode2 = bilibili_client2.GET();
  if(httpCode2 > 0 && httpCode2==HTTP_CODE_OK)
  {
    String response = bilibili_client2.getString();
    DebugPrintln(response);
    JsonObject& root = jsonBuffer.parseObject(response);
    BILI_NOW_DATE.follower = root["data"]["follower"];
    BILI_NOW_DATE.following = root["data"]["following"];
  }
  bilibili_client2.end();
}

/*
@功能:桌面1
@参数：time_show：系统时间
       userData：天气情况
*/
void Desktop1(void){
  //给RGB点阵上显示时间
  if(RGB_KEY==1){
    RGB_ShowNum(0,0,TIME_NOW.hours,2);
    RGB_ShowChar(12,0,':');
    RGB_ShowNum(18,0,TIME_NOW.minutes,2);
  }

  u8g2.clearBuffer();
  //画天气图案（没有网络的话显示断网）
  if(WIFI_MODE == 1)
      drawWeather();
  else
  {
    u8g2.setFont(u8g2_font_open_iconic_all_2x_t);
    u8g2.drawGlyph(0, 16, 197);
  }

    //显示 年-月-日
    u8g2.setFont(u8g2_font_6x10_mf);
    u8g2.setCursor(67, 11);
    u8g2.print(TIME_NOW.years);
    
    u8g2.drawStr(91,11,".");
    
    u8g2.setCursor(97, 11);
    if(TIME_NOW.months>=10)
      u8g2.print(TIME_NOW.months);
    else{
      u8g2.print("0");
      u8g2.setCursor(104,11);
      u8g2.print(TIME_NOW.months);
    }
    
    u8g2.drawStr(109,11,".");

    u8g2.setCursor(115, 11);
    if(TIME_NOW.days>=10)
      u8g2.print(TIME_NOW.days);
    else{
      u8g2.print("0");
      u8g2.setCursor(123,11);
      u8g2.print(TIME_NOW.days);
    }

    //显示 IP地址
    u8g2.drawStr(0,63,"IP:");
    u8g2.setCursor(22, 63);
    u8g2.print(WiFi.localIP());

    //显示 星期（day of week）
    u8g2.setFont(u8g2_font_wqy12_t_gb2312);
    u8g2.setCursor(114, 63);
    u8g2.print(num_week(TIME_NOW.weeks,4)); 
    
    //显示 时-分-秒
    u8g2.setFont(u8g2_font_inb21_mn);
    u8g2.setCursor(3,45);
    if(TIME_NOW.hours>=10)
      u8g2.print(TIME_NOW.hours);
    else{
      u8g2.print("0");
      u8g2.setCursor(23,45);
      u8g2.print(TIME_NOW.hours);
    }
    u8g2.drawStr(42,43,":");
    u8g2.setCursor(60,45);
    if(TIME_NOW.minutes>=10)
      u8g2.print(TIME_NOW.minutes);
    else{
      u8g2.print("0");
      u8g2.setCursor(80,45);
      u8g2.print(TIME_NOW.minutes);
    }
    u8g2.setFont(u8g2_font_ncenR12_tf);
    u8g2.drawStr(100,45,":");
    u8g2.setCursor(110,45);
    if(TIME_NOW.seconds>=10)
      u8g2.print(TIME_NOW.seconds);
    else{
      u8g2.print("0");
      u8g2.setCursor(120,45);
      u8g2.print(TIME_NOW.seconds);
    }
    //显示电量
    //u8g2.drawRBox(100,18,(Battery_capacity*20)/1024,8,3);
    u8g2.drawRBox(102,20,20,8,3);
    u8g2.drawRBox(122,22,2,4,1);
    u8g2.sendBuffer();
}

/*
@功能:桌面2(bilibili粉丝数)
*/
void Desktop2(void){
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_wqy14_t_gb2312a);

  u8g2.drawXBMP(36,-1, bilibili_bmp_x, bilibili_bmp_y, bilibili_bmp);

  u8g2.setCursor(10, 16*2+1);
  u8g2.print("粉丝数:");
  u8g2.setCursor(70, 16*2+1);
  u8g2.print(BILI_NOW_DATE.follower);

  u8g2.setCursor(10, 16*3-1);
  u8g2.print("点赞数:");
  u8g2.setCursor(70, 16*3-1);
  u8g2.print(BILI_NOW_DATE.likes);

  u8g2.setCursor(10, 16*4-2);
  u8g2.print("播放量:");
  u8g2.setCursor(70, 16*4-2);
  u8g2.print(BILI_NOW_DATE.view);
  u8g2.sendBuffer();
}

/*
@功能:设置界面
*/
void set_page(void){
  int8_t x,y;
  bool x_r,y_r;
  page_int("设置",1,12,millis());//初始化页
  DebugPrintln("*************进入设置***************");
  openDisplay.detach();//关定时器
  u8g2.setPowerSave(LOW);//开显示屏
  
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_open_iconic_all_6x_t);
  u8g2.drawGlyph(40,55,129);
  u8g2.sendBuffer();
  delay(1000);
      
  while(true){
  //防止光标位置错
  //set_up_page.cursor = set_up_page.cursor<=1 ? 1:set_up_page.cursor;
  set_up_page.cursor = set_up_page.cursor < 1 ? set_up_page.rows:set_up_page.cursor;
  //set_up_page.cursor = set_up_page.cursor>=set_up_page.rows ? set_up_page.rows:set_up_page.cursor;
  set_up_page.cursor = set_up_page.cursor > set_up_page.rows ? 1:set_up_page.cursor;
  
  //刷新屏幕millis()-set_up_page.time >= set_up_page.refresh_time
  if(millis()-set_up_page.time >= set_up_page.refresh_time){
    set_up_page.time = millis();
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
    uint8_t PAGE = (set_up_page.cursor%4 == 0 ? (set_up_page.cursor/4)-1:set_up_page.cursor/4);
    switch(PAGE)
    {
      case 0:
      u8g2.setCursor(20, 16*1-2);
      u8g2.print(" 1.桌面设置");
      u8g2.setCursor(20, 16*2-2);
      u8g2.print(" 2.屏幕设置");
      u8g2.setCursor(20, 16*3-2);
      u8g2.print(" 3.网络信息");
      u8g2.setCursor(20, 16*4-2);
      u8g2.print(" 4.智能配网");
      break;
      case 1:
      u8g2.setCursor(20, 16*1-2);
      u8g2.print(" 5.时间设置");
      u8g2.setCursor(20, 16*2-2);
      u8g2.print(" 6.天气设置");
      u8g2.setCursor(20, 16*3-2);
      u8g2.print(" 7.刷新时间");
      u8g2.setCursor(20, 16*4-2);
      u8g2.print(" 8.版本信息");
      break;
      case 2:
      u8g2.setCursor(20, 16*1-2);
      u8g2.print(" 9.RGB点阵屏");
      u8g2.setCursor(18, 16*2-2);
      u8g2.print("10.视频播放");
      u8g2.setCursor(18, 16*3-2);
      u8g2.print("11.烧屏测试");
      u8g2.setCursor(18, 16*4-2);
      u8g2.print("12.退出设置");
      break;
    }
    //显示光标
    u8g2.setFont(u8g2_font_open_iconic_all_1x_t);
    u8g2.drawGlyph(5, 16*(set_up_page.cursor%4==0? 4:set_up_page.cursor%4)-4,118);
    u8g2.sendBuffer();
  }
  
  uint8_t KEY=KEY_Scan2();//扫描按键2
  if(KEY == WAKE_UP_LONG_PRES)
    break;
  else if(KEY == M_KEY_LONG_PRES)
    break;
  switch(KEY)
  {
    case UP_KEY_PRES:
      set_up_page.cursor --;
    break;
    case M_KEY_PRES:
      u8g2.clearBuffer();
      u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
      u8g2.setCursor(0,0);
      u8g2.print(set_up_page.cursor);
      u8g2.sendBuffer();      
      switch(set_up_page.cursor){
        case 1:
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);

              u8g2.setCursor(24, 16*1-2);
              u8g2.print("     桌面");
              u8g2.setCursor(20, 16*2-2);
              u8g2.print(" 1.天气时钟");
              u8g2.setCursor(20, 16*3-2);
              u8g2.print(" 2.bilibili粉丝");

              //显示光标
              u8g2.setFont(u8g2_font_open_iconic_all_1x_t);
              u8g2.drawGlyph(5, 16*(Desktop_Mode+1)-4,118);

              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == DOWN_KEY_PRES){
              Desktop_Mode ++;
              Desktop_Mode = Desktop_Mode > 2 ? 2:Desktop_Mode;
            }
            if(KEY == UP_KEY_PRES){
              Desktop_Mode --;
              Desktop_Mode = Desktop_Mode < 1 ? 1:Desktop_Mode;
            }
            ESP.wdtFeed();// 喂 狗
          }
          u8g2.clearBuffer();
          switch (Desktop_Mode)
          {
          case TIME_WEATHER:
            u8g2.setFont(u8g2_font_cupcakemetoyourleader_tr);
            u8g2.drawStr(50,36,"Weather");
            u8g2.setFont(u8g2_font_open_iconic_all_6x_t);
            u8g2.drawGlyph(0, 52, 187);//正无穷标志
          break;
          case BILIBILI:
            u8g2.drawXBMP(32,-1, bilibili_head_x, bilibili_head_y, bilibili_head);
          break;
          default:
          break;
          }
          u8g2.sendBuffer();
          delay(1000);
          DATA_UPDATA = 1;
        break;
        case 2://亮度设置搞定
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
              u8g2.setCursor(0,27);
              u8g2.print("屏幕亮度:");

              u8g2.setCursor(64,27);
              u8g2.print((OLED_Brightness*100)/255);
              u8g2.setCursor((OLED_Brightness*100)/255>=100 ? 88:80,27);
              u8g2.print("%");

              u8g2.drawRBox(0,36,(OLED_Brightness*128)/255,16,5);

              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == UP_KEY_PRES){
              OLED_Brightness += 20;
              OLED_Brightness = OLED_Brightness > 255 ? 255:OLED_Brightness;
              u8g2.setContrast(OLED_Brightness);//设置OLED亮度
            }
            if(KEY == DOWN_KEY_PRES){
              OLED_Brightness -= 20;
              OLED_Brightness = OLED_Brightness < 21 ? 20:OLED_Brightness;
              u8g2.setContrast(OLED_Brightness);//设置OLED亮度
            }
            ESP.wdtFeed();// 喂 狗
          }
        break;
        case 3://已完成WIFI信息
          u8g2.clearBuffer();
          u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
          u8g2.setCursor(36,16*1-2);
          u8g2.print("WIFI信息");
          u8g2.setCursor(0,16*2-2);
          u8g2.print("SSID:");
          u8g2.setCursor(37,16*2-2);
          u8g2.print(WiFi.SSID().c_str());
          u8g2.setCursor(0,16*3-2);
          u8g2.print("PSWD:");
          u8g2.setCursor(42,16*3-2);
          u8g2.print(WiFi.psk().c_str());
          u8g2.setCursor(0,16*4-2);
          u8g2.print("IP:");
          u8g2.setCursor(18,16*4-2);
          u8g2.print(WiFi.localIP());
          u8g2.sendBuffer();
          while(true){
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            ESP.wdtFeed();// 喂 狗
          }
        break;
        case 4://已完成配网
          Get_SmartConfig = true;
          goto TIAOCHU;
        break;
        case 5://时间模式完成
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
              u8g2.setCursor(36,16*1-2);
              u8g2.print("时间模式");
              if(TIME_MODE==DS3231_TIME_MODE){
                u8g2.setCursor(36,16*3-2);
                u8g2.print("DS3231源");
              }
              else{
                u8g2.setCursor(32,16*3-2);
                u8g2.print("NTP网络源");
              }
              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == UP_KEY_PRES)
              TIME_MODE = !TIME_MODE;
            if(KEY == DOWN_KEY_PRES)
              TIME_MODE = !TIME_MODE;
            ESP.wdtFeed();// 喂 狗
          }
        break;
        case 6:
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
              u8g2.setCursor(0,16*2-2);
              u8g2.print("城市名称:");
              u8g2.setCursor(70,16*2-2);
              u8g2.print(citys[which_city-1].city_name);
              u8g2.setCursor(0,16*3-2);
              u8g2.print("城市ID:");
              u8g2.setCursor(55,16*3-2);
              u8g2.print(citys[which_city-1].city_id);
              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == UP_KEY_PRES){
              which_city += 1;
              which_city = which_city >= city_num ? city_num:which_city;
            }
            if(KEY == DOWN_KEY_PRES){
              which_city -= 1;
              which_city = which_city <= 1 ? 1:which_city;
            }
            ESP.wdtFeed();// 喂 狗
          }
          u8g2.clearBuffer();
          u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
          u8g2.setCursor(0,16*3-8);
          u8g2.print("城市设置为:");
          u8g2.setCursor(90,16*3-8);
          u8g2.print(citys[which_city-1].city_name);
          u8g2.sendBuffer();
          delay(1000);
        break;
        case 7:
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
              u8g2.setCursor(0,40);
              u8g2.print("更新时间:");
              u8g2.setCursor(WeatherDelay/(60*1000)>=10 ? 64:72,40);
              u8g2.print(WeatherDelay/(60*1000));
              u8g2.setCursor(80,40);
              u8g2.print(WeatherDelay%(60*1000)==0 ? ".0":".5");
              u8g2.setCursor(96,40);
              u8g2.print("分钟");
              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == UP_KEY_PRES){
              WeatherDelay += 30*1000;
              WeatherDelay = WeatherDelay >=10*60*1000 ? 10*60*1000:WeatherDelay;
            }
            if(KEY == DOWN_KEY_PRES){
              WeatherDelay -= 30*1000;
              WeatherDelay = WeatherDelay <=30*1000 ? 30*1000:WeatherDelay;
            }
            ESP.wdtFeed();// 喂 狗
          }
        break;
        case 8://固件版本完成
          u8g2.clearBuffer();
          u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
          u8g2.setCursor(36,16*1-2);
          u8g2.print("版本信息");
          u8g2.setCursor(0,16*2-2);
          u8g2.print("固件版本:");
          u8g2.setCursor(63,16*2-2);
          u8g2.print(Firmware_version);
          u8g2.setCursor(0,16*3-2);
          u8g2.print("固件大小:");
          u8g2.setCursor(63,16*3-2);
          u8g2.print(ESP.getSketchSize()/1024);
          u8g2.setCursor(84,16*3-2);
          u8g2.print("KBytes");
          u8g2.setCursor(0,16*4-2);
          u8g2.print("作者:");
          u8g2.setCursor(35,16*4-2);
          u8g2.print("刘泽文");
          u8g2.sendBuffer();
          while(true){
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            ESP.wdtFeed();// 喂 狗
          }
        break;
        case 9://点阵开关完成
          while(true){
            if(millis()-set_up_page.time >= set_up_page.refresh_time){
              set_up_page.time = millis();//重新赋值
              u8g2.clearBuffer();
              u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
              u8g2.setCursor(0,40);
              u8g2.print("RGB点阵屏:");
              u8g2.setCursor(85,40);
              if(RGB_KEY==1)
                u8g2.print("-开-");
              else
                u8g2.print("-关-");
              u8g2.sendBuffer();
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            if(KEY == UP_KEY_PRES){
              RGB_KEY = !RGB_KEY;
              }
            if(KEY == DOWN_KEY_PRES){
              RGB_KEY = !RGB_KEY;
              }
            ESP.wdtFeed();// 喂 狗
          }
          if(RGB_KEY==0)
            WS2812_INT();//WS2812 RGB点阵初始化,以息屏
        break;
        case 10:
          u8g2.clearBuffer();
          u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
          u8g2.setCursor(36,40);
          u8g2.print("视频播放");
          u8g2.setCursor(88,40);
          u8g2.sendBuffer();
          while(true){
            if(badapple_Status==0 && WiFi.status()==WL_CONNECTED){
              badapple_Status=1;
              badapple_client.connect(badapple_Server, badapple_Port);
            }
            while(badapple_client.available()){ 
              badapple_client.read(badapple,1024);
              delay(75);
              u8g2.clearBuffer();
              u8g2.drawXBMP(0, 0, 128, 64, badapple);
              u8g2.sendBuffer();
              ESP.wdtFeed();// 喂 狗
            }
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
            ESP.wdtFeed();// 喂 狗
          }
          badapple_client.stop(); 
        break;
        case 11:
          u8g2.clearBuffer();
          u8g2.drawRBox(0,-1,128,64,3);
          u8g2.sendBuffer();
          delay(3000);
          x = 0;
          y = 0;
          x_r = 1;
          y_r = 1;
          while(1){
            if(x_r)x++;else x--;
            if(y_r)y++;else y--;
            if(x>=127-8)x_r = 0;
            if(x<=0+8)x_r = 1;
            if(y>=63-8)y_r = 0;
            if(y<=0+8)y_r = 1;
            u8g2.clearBuffer();
            u8g2.drawDisc(x,y,5);
            u8g2.drawCircle(x,y,8);
            u8g2.sendBuffer();
            ESP.wdtFeed();// 喂 狗
            uint8_t KEY=KEY_Scan2();//扫描按键
            if(KEY == M_KEY_PRES)
              break;
          }
          for(int i = 0;i<=3;i++){
            for (int frame=0; frame < 36; frame++)
            {
              HariChord(frame);
              ESP.wdtFeed();// 喂 狗     
            }
 
            for (int frame=(36-1); frame >= 0; frame--)
            {
              HariChord(frame);
              ESP.wdtFeed();// 喂 狗     
            }
          }
        break;
        case 12:
          goto TIAOCHU;//goto语法跳出设置
        break;
      }
    break;
    case DOWN_KEY_PRES:
      set_up_page.cursor ++;
    break;
  }
    ESP.wdtFeed();// 喂 狗
  }
  TIAOCHU://goto语法
  DebugPrintln("*************退出设置***************");
  u8g2.firstPage();
  do{
    u8g2.setFont(u8g2_font_open_iconic_all_6x_t);
    u8g2.drawGlyph(35,60,64);
  }while (u8g2.nextPage());
  delay(1000);
}

/*
@功能:网络时间获取更新
*/
void update_time(void){
    prevDisplay = now();
    Serial.println("***********更新时间***********");
    Serial.print("网络时间是:   ");
    Serial.print(year());
    Serial.print(".");
    Serial.print(month());
    Serial.print(".");
    Serial.print(day());
    Serial.print(" ");
    Serial.print(hour());
    Serial.print(":");
    Serial.print(minute());
    Serial.print(":");
    Serial.print(second());
    Serial.print("    星期");
    Serial.println(num_week(weekday(),4));
    
    Clock.setClockMode(false);  // set to 24h
    Clock.setYear(year()-2000);
    Clock.setMonth(month());
    Clock.setDate(day());
    Clock.setDoW(weekday());
    Clock.setHour(hour());
    Clock.setMinute(minute());
    Clock.setSecond(second());
}

/*
@功能:autoConfig 默认WIFI连网
@说明:自动连接20s超过之后自动进入无网络模式
*/
bool autoConfig(void){
  WiFi.mode(WIFI_STA);     // 设 置 esp8266 工 作 模 式
  DebugPrint("联网至:");DebugPrintln(WiFi.SSID().c_str());DebugPrintln(WiFi.psk().c_str());
  WiFi.begin(config.stassid,config.stapsw);//连接指定的WIFI
  //WiFi.begin(WiFi.SSID().c_str(),WiFi.psk().c_str());//连接上次连接的WIFI
  //WiFi.begin();
  delay(500);// 刚 启 动 模 块 的 话 延 时 稳 定 一 下
  u8g2.firstPage();
  do{
    u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
    u8g2.setCursor(30, 36);
    u8g2.print("联网中......"); 
  }while (u8g2.nextPage());
  DebugPrint("AutoConfiging");
  for(int index=0;index<100;index++){//连接20s
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED){
      DebugPrintln("\nAutoConfig Success");
      DebugPrint("SSID:");
      DebugPrintln(WiFi.SSID().c_str());
      DebugPrint("PSW:");
      DebugPrintln(WiFi.psk().c_str());
      return true;
    }else{
      DebugPrint(".");
      delay(200);
      LED_PWM;
    } 
  }
  DebugPrintln("自动联网->失败!");

  u8g2.firstPage();
  do{
    u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
    u8g2.setCursor(16, 36);
    u8g2.print("联网失败......"); 
  }while (u8g2.nextPage());

  return false; 
}

/*
@功能:SmartConfig 智能配网
*/
void smartConfig(void){
  WiFi.mode(WIFI_STA);
  delay(1000);
  DebugPrintln("Wait for Smartconfig");
  WiFi.beginSmartConfig();
  Get_SmartConfig = LOW;//清标志位
  u8g2.firstPage();
  do{
    u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
    u8g2.setCursor(14, 36);
    u8g2.print("智能配网中......"); 
  }while (u8g2.nextPage());
  while (true){
    DebugPrint(".");
    delay(200);
    LED_PWM;//闪灯~~
    if(WiFi.smartConfigDone()){//smartconfig 配 置 完 毕
     DebugPrintln("SmartConfig Success");
     DebugPrint("SSID:");
     DebugPrintln(WiFi.SSID().c_str());
     DebugPrint("PSW:");
     DebugPrintln(WiFi.psk().c_str());
     strcpy(config.stassid, WiFi.SSID().c_str());   
     strcpy(config.stapsw, WiFi.psk().c_str());
     WiFi.mode(WIFI_AP_STA);// 设 置 esp8266 工 作 模 式
     WiFi.setAutoConnect(true);
     WiFi.setAutoReconnect(true);// 设 置 自 动 连 接
     u8g2.firstPage();
     do{
       u8g2.setFont(u8g2_font_wqy14_t_gb2312a);
       u8g2.setCursor(36, 16);
       u8g2.print("配网成功"); 
       u8g2.setCursor(0, 36);
       u8g2.print(WiFi.SSID().c_str());
       u8g2.setFont(u8g2_font_crox3t_tf );
       u8g2.setCursor(0, 60);
       u8g2.print(WiFi.psk().c_str()); 
    }while (u8g2.nextPage());
     DATA_UPDATA = 1;
     WIFI_MODE = 1;  
     break;  
     }
     ESP.wdtFeed();//喂狗  
   }
}

/*
@功能:发送请求指令
*/
bool sendRequest(const char* host, const char* cityid, const char* apiKey){
  // We now create a URI for the request   
  // 心 知 天 气
   String GetUrl = "/v3/weather/now.json?key=";   
   GetUrl += apiKey;
   GetUrl += "&location=";
   GetUrl += cityid;
   GetUrl += "&language=";
   GetUrl += language;
   // This will send the request to the server
   client.print(String("GET ") + GetUrl + " HTTP/1.1\r\n" + 
                "Host: " + host + "\r\n" +
                "Connection: close\r\n\r\n");
   DebugPrintln("create a request:");
   DebugPrintln(String("GET ") + GetUrl + " HTTP/1.1\r\n" +
                "Host: " + host + "\r\n" +
                "Connection: close\r\n");
   delay(1000);
   return true; 
}

/*
@功能:Desc跳过HTTP头，使我们在响应正文的开头
*/
bool skipResponseHeaders(){
  // HTTP headers end with an empty line
  bool ok = client.find(endOfHeaders);
  if(!ok){
    DebugPrintln("No response or invalid response!");
    }
    return ok;
}

/*
@功能:Desc从HTTP服务器响应中读取正文
*/
void readReponseContent(char* content, size_t maxSize){
  size_t length = client.readBytes(content, maxSize);
  delay(100);
  DebugPrintln("Get the data from Internet!");
  content[length] = 0;
  DebugPrintln(content);
  DebugPrintln("Read data Over!");
  client.flush();
  //这句代码需要加上不然会发现每隔一次client.find会失败
 }
 
 //关闭与HTTP服务器连接
 void stopConnect(){
  client.stop(); 
}   

void clrEsp8266ResponseBuffer(void){
  memset(response, 0, MAX_CONTENT_SIZE);//清空
}

bool parseUserData(char* content){
//--根据我们需要解析的数据来计算JSON缓冲区佳大小
//如果你使用StaticJsonBuffer时才需要
//const size_t BUFFER_SIZE=1024;
//在堆栈上分配一个临时内存池
//StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
//--如果堆栈的内存池太大，使用DynamicJsonBuffer jsonBuffer代替
   DynamicJsonBuffer jsonBuffer;
   
   JsonObject& root = jsonBuffer.parseObject(content);
   if (!root.success()){
    Serial.println("JSON parsing failed!");
    return false;
    }       
    //复制我们感兴趣的字符串
   strcpy(userData.city, root["results"][0]["location"]["name"]);
   strcpy(userData.weather_code, root["results"][0]["now"]["code"]);
   strcpy(userData.temp, root["results"][0]["now"]["temperature"]);
   return true;
}

/*
@功能:对所有天气情况按照显示图标进行分类
*/
void classified_weather(void){
  if(strcmp(userData.weather_code,WEATHER_CODE_DAY_SUN) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_DAY_SUN1) == 0){
    userData.weather = SUN_DAY;
  }else if(strcmp(userData.weather_code,WEATHER_CODE_NIGHT_SUN) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_NIGHT_SUN2) == 0 ){
    userData.weather = SUN_NIGHT;
  }else if(strcmp(userData.weather_code,WEATHER_CODE_DAY_PARTLY_CLOUDY) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_NIGHT_PARTLY_CLOUDY)== 0){
    userData.weather = SUN_CLOUD;
  }else if(strcmp(userData.weather_code,WEATHER_CODE_CLOUDY) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_DAY_MOSTLY_CLOUDY) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_NIGHT_MOSTLY_CLOUDY) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_OVERCAST) == 0){
    userData.weather = CLOUD;
  }else if(strcmp(userData.weather_code,WEATHER_CODE_SHOWER) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_LIGHT_RAIN) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_MODERATE_RAIN) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_HEAVY_RAIN) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_STORM) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_HEAVY_STORM) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_SEVERE_STORM) == 0){
    userData.weather = RAIN;
  }else if(strcmp(userData.weather_code,WEATHER_CODE_THUNDERSHOWER) == 0
  || strcmp(userData.weather_code,WEATHER_CODE_THUNDERSHOWER_WITH_HAIL) == 0){
    userData.weather = THUNDER;
  }else{
    userData.weather = CLOUD;
  } 
}

/*
@功能:绘制天气信息图标
*/
void drawWeather(void){
  u8g2.setFont(u8g2_font_open_iconic_weather_2x_t);
  switch(userData.weather)
  {
    case SUN_DAY:// 太 阳
       u8g2.drawGlyph(0, 16, 69);
       break;
    case SUN_NIGHT:// 太 阳
       u8g2.drawGlyph(0, 16, 66);
       break;
    case SUN_CLOUD:// 晴 间 多 云
       u8g2.drawGlyph(0, 16, 65);
       break;
    case CLOUD:// 多 云
       u8g2.drawGlyph(0, 16, 64);
       break;
    case RAIN:// 下 雨
       u8g2.drawGlyph(0, 16, 67);
       break;
    case THUNDER:// 打 雷
       u8g2.drawGlyph(0, 16, 67);
       break;         
   }
  u8g2.setFont(u8g2_font_9x15_t_symbols);// 绘 制 温 度
  u8g2.setCursor(20, 13);
  u8g2.print(userData.temp);
  u8g2.print("°C");
}

/*
@功能：几何动画
*/
void HariChord(int frame)
{
  int nFrames = 36;
  u8g2.clearBuffer();
  int n = 7;
  int r = frame * 64 / nFrames;
  float rot = frame * 2*PI / nFrames;
  for (int i=0; i<(n-1); i++)
  {
    float a = rot + i * 2*PI / n;
    int x1 = 64 + cos(a) * r;
    int y1 = 32 + sin(a) * r;
    for (int j=i+1; j<n; j++)
    {
      a = rot + j * 2*PI / n;
      int x2 = 64 + cos(a) * r;
      int y2 = 32 + sin(a) * r;
      u8g2.drawLine(x1,y1, x2,y2);
    }
    ESP.wdtFeed();// 喂 狗     
  }
  u8g2.sendBuffer();
}

/*
@功能：开机动画
*/
void boot_animation(){
  //爱心眼睛
  const static unsigned char FACE_Love[] PROGMEM ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0xFF,0x00,0x00,0x00,0xFC,0xFF,0x3F,0x00,0x00,0x00,0xFE,0xFF,0xFF,0x03,0x00,0x80,0xFF,0xFF,0xFF,0x01,0x00,0x80,0xFF,0xFF,0xFF,0x0F,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0xC0,0x07,0x00,0x00,0x1F,0x00,0xE0,0x03,0x00,0xC0,0x07,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0xF0,0x00,0x00,0x00,0x0F,0x00,0xE0,0x00,0x00,0x00,0x38,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0xE0,0x07,0x3F,0xE0,0x00,0x0C,0xF0,0x81,0x0F,0x30,0x00,0x38,0xF0,0x8B,0x5F,0xE0,0x00,0x0C,0xF8,0xC2,0x1F,0x30,0x00,0x38,0xF8,0xD7,0xBF,0xE0,0x00,0x0C,0xFC,0xE5,0x2F,0x30,0x00,0x38,0xF8,0xFF,0xBF,0xE0,0x00,0x0C,0xFE,0xFF,0x5F,0x30,0x00,0x38,0xFC,0xFF,0x7F,0xE0,0x00,0x0C,0xFE,0xFF,0x5F,0x30,0x00,0x38,0xFC,0xFF,0xFF,0xE1,0x00,0x0C,0xFE,0xFF,0x7F,0x30,0x00,0x38,0xFC,0xFF,0xFF,0xE1,0x00,0x0C,0xFE,0xFF,0x7F,0x30,0x00,0x38,0xFC,0xFF,0xFF,0xE1,0x00,0x0C,0xFE,0xFF,0x7F,0x30,0x00,0x38,0xF8,0xFF,0xFF,0xE0,0x00,0x0C,0xFE,0xFF,0x7F,0x30,0x00,0x38,0xF8,0xFF,0xFF,0xE0,0x00,0x0C,0xFE,0xFF,0x7F,0x30,0x00,0x38,0xF8,0xFF,0xFF,0xE0,0x00,0x0C,0xFC,0xFF,0x3F,0x30,0x00,0x38,0xF0,0xFF,0x7F,0xE0,0x00,0x0C,0xF8,0xFF,0x1F,0x30,0x00,0x38,0xC0,0xFF,0x1F,0xE0,0x00,0x0C,0xF0,0xFF,0x0F,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xE0,0xFF,0x07,0x30,0x00,0x38,0x00,0xFF,0x07,0xE0,0x00,0x0C,0xC0,0xFF,0x03,0x30,0x00,0x38,0x00,0xFE,0x03,0xE0,0x00,0x0C,0x80,0xFF,0x01,0x30,0x00,0x38,0x00,0xFC,0x01,0xE0,0x00,0x0C,0x00,0x7E,0x00,0x30,0x00,0x38,0x00,0xF8,0x00,0xE0,0x00,0x0C,0x00,0x3C,0x00,0x30,0x00,0x38,0x00,0x70,0x00,0xE0,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x38,0x00,0x20,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x3C,0x00,0x00,0x00,0x3C,0x00,0xF0,0x00,0x00,0x00,0x78,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0xC0,0x03,0x00,0x00,0x1E,0x00,0xF0,0x01,0x00,0x80,0x0F,0x00,0x80,0x1F,0x00,0xC0,0x0F,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0x00,0xFF,0xFF,0xFF,0x07,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0x00,0xFC,0xFF,0xFF,0x01,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  //睁眼
  const static unsigned char FACE_Neutral[] PROGMEM ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0xFF,0x00,0x00,0x00,0xFC,0xFF,0x3F,0x00,0x00,0x00,0xFE,0xFF,0xFF,0x03,0x00,0x80,0xFF,0xFF,0xFF,0x01,0x00,0x80,0xFF,0xFF,0xFF,0x0F,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0xC0,0x07,0x00,0x00,0x1F,0x00,0xE0,0x03,0x00,0xC0,0x07,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0xF0,0x00,0x00,0x00,0x0F,0x00,0xE0,0x00,0x00,0x00,0x38,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x84,0x00,0xE0,0x00,0x0C,0x00,0x41,0x00,0x30,0x00,0x38,0x00,0x70,0x00,0xE0,0x00,0x0C,0x00,0x38,0x01,0x30,0x00,0x38,0x00,0xFC,0x01,0xE0,0x00,0x0C,0x00,0x7F,0x00,0x30,0x00,0x38,0x00,0xFE,0x03,0xE0,0x00,0x0C,0xA0,0xFF,0x05,0x30,0x00,0x38,0x00,0x7F,0x06,0xE0,0x00,0x0C,0x80,0x3F,0x01,0x30,0x00,0x38,0x40,0x7F,0x17,0xE0,0x00,0x0C,0xC0,0xDF,0x03,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xD0,0xFF,0x0B,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xC0,0xFF,0x03,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xD0,0xFF,0x0B,0x30,0x00,0x38,0x00,0xFF,0x07,0xE0,0x00,0x0C,0xC0,0xFF,0x03,0x30,0x00,0x38,0x40,0xFF,0x17,0xE0,0x00,0x0C,0x80,0xFF,0x01,0x30,0x00,0x38,0x00,0xFE,0x03,0xE0,0x00,0x0C,0xA0,0xFF,0x05,0x30,0x00,0x38,0x00,0xFC,0x01,0xE0,0x00,0x0C,0x00,0xFF,0x00,0x30,0x00,0x38,0x00,0x70,0x00,0xE0,0x00,0x0C,0x80,0x3C,0x01,0x30,0x00,0x38,0x00,0x84,0x00,0xE0,0x00,0x0C,0x00,0x42,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x3C,0x00,0x00,0x00,0x3C,0x00,0xF0,0x00,0x00,0x00,0x78,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0xC0,0x03,0x00,0x00,0x1E,0x00,0xF0,0x01,0x00,0x80,0x0F,0x00,0x80,0x1F,0x00,0xC0,0x0F,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0x00,0xFF,0xFF,0xFF,0x07,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0x00,0xFC,0xFF,0xFF,0x01,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  //闭眼
  const static unsigned char FACE_Tired_middle[] PROGMEM ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0xFF,0x00,0x00,0x00,0xFC,0xFF,0x3F,0x00,0x00,0x00,0xFE,0xFF,0xFF,0x03,0x00,0x80,0xFF,0xFF,0xFF,0x01,0x00,0x80,0xFF,0xFF,0xFF,0x0F,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0xC0,0x07,0x00,0x00,0x1F,0x00,0xE0,0x03,0x00,0xC0,0x07,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0xF0,0x00,0x00,0x00,0x0F,0x00,0xE0,0x00,0x00,0x00,0x38,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x1C,0x00,0x00,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x30,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x0C,0x00,0x00,0x00,0x38,0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0x00,0xFC,0xFF,0xFF,0xFF,0x3F,0x00,0xF8,0xFF,0xFF,0xFF,0xFF,0x00,0xFC,0xFF,0xFF,0xFF,0x3F,0x00,0x38,0x40,0xFF,0x17,0xE0,0x00,0x1C,0xD0,0xDF,0x0B,0x38,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xC0,0xFF,0x0B,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xD0,0xFF,0x03,0x30,0x00,0x38,0x80,0xFF,0x0F,0xE0,0x00,0x0C,0xD0,0xFF,0x0B,0x30,0x00,0x38,0x00,0xFF,0x07,0xE0,0x00,0x0C,0xC0,0xFF,0x03,0x30,0x00,0x38,0x40,0xFF,0x17,0xE0,0x00,0x0C,0x80,0xFF,0x01,0x30,0x00,0x38,0x00,0xFE,0x03,0xE0,0x00,0x1C,0xA0,0xFF,0x05,0x38,0x00,0x70,0x00,0xFC,0x01,0x70,0x00,0x1C,0x00,0xFF,0x00,0x38,0x00,0x70,0x00,0x70,0x00,0x70,0x00,0x3C,0x80,0x3C,0x01,0x3C,0x00,0xF0,0x00,0x84,0x00,0x78,0x00,0x38,0x00,0x42,0x00,0x1C,0x00,0xE0,0x01,0x00,0x00,0x3C,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0xC0,0x03,0x00,0x00,0x1E,0x00,0xF0,0x01,0x00,0x80,0x0F,0x00,0x80,0x1F,0x00,0xC0,0x0F,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0x00,0xFF,0xFF,0xFF,0x07,0x00,0xC0,0xFF,0xFF,0xFF,0x03,0x00,0x00,0xFC,0xFF,0xFF,0x01,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Neutral);}
  while (u8g2.nextPage());
  delay(400);
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Tired_middle);}
  while (u8g2.nextPage());
  delay(100);
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Neutral);}
  while (u8g2.nextPage());
  delay(400);
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Tired_middle);}
  while (u8g2.nextPage());
  delay(100);
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Neutral);}
  while (u8g2.nextPage());
  delay(400);
  u8g2.firstPage();
  do{u8g2.drawXBMP(20,0,89,64,FACE_Love);}
  while (u8g2.nextPage());
  delay(300);
}

/*
@功能：打印系统参数，固件版本信息
*/
void print_firmware_information(void){
  FlashMode_t ideMode = ESP.getFlashChipMode();
  String coreVersion = ESP.getCoreVersion();
  Serial.println("\n");
  Serial.print(F("Arduino Core For ESP8266 Version: "));
  Serial.println(coreVersion);
  Serial.printf("\nESP8266芯片id: %u \n\n", ESP.getChipId());
  Serial.printf("天气时钟固件版本: %s \n\n", Firmware_version);
  Serial.print("固件编译时间：");
  Serial.print(__DATE__);
  Serial.print("   ");
  Serial.println(__TIME__);
  Serial.println();
  Serial.printf("固件大小: %u KBytes\n\n", ESP.getSketchSize()/1024);
  Serial.printf("剩余可用固件空间: %u KBytes\n\n", ESP.getFreeSketchSpace()/1024);
  Serial.printf("Flash real id:   %08X\n\n", ESP.getFlashChipId());
  Serial.printf("Flash 实际大小: %u KBytes\n\n", ESP.getFlashChipRealSize()/1024);
  Serial.printf("IDE配置Flash大小: %u KBytes\n\n", ESP.getFlashChipSize()/1024);
  Serial.printf("IDE配置Flash频率: %u MHz\n\n", ESP.getFlashChipSpeed()/1000000);
  Serial.printf("Flash ide mode:  %s\n\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));
}

/*
@功能：OTA无线升级程序
@说明:太复杂，不看~
*/
void BasicOTAINT(void){
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }
    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("OTA Ready");
}

/*
@说明：WS2812 RGB点阵初始化
*/
void WS2812_INT(void){
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
  FastLED.setBrightness( BRIGHTNESS );
}

/*
@说明：WS2812 RGB点阵屏XY转地址函数（XY->i)  使用时可直接调用下面的RGBXYsafe
*/
uint16_t RGBXY( uint8_t x, uint8_t y)
{
  uint16_t i;
  
  if( kMatrixSerpentineLayout == false) {
    i = (x * kMatrixWidth) + y;
  }

  if( kMatrixSerpentineLayout == true) {
    if( x & 0x01) {
      // Odd rows run backwards
      uint8_t reverseY = (kMatrixWidth - 1) - y;
      i = (x * kMatrixWidth) + reverseY;
    } else {
      // Even rows run forwards
      i = (x * kMatrixWidth) + y;
    }
  }
  
  return i;
}

/*
@说明：WS2812 RGB点阵屏XY 判断输入XY是否超出最大值 超出返回-1 此时设置点阵不显示
*/
uint16_t RGBXYsafe( uint8_t x, uint8_t y)
{
  if( x >= kMatrixHeight||y >= kMatrixWidth) return RGBXY(x+1-kMatrixHeight,y+1-kMatrixWidth);
  else return RGBXY(x,y);
}

/*
@说明：RGB写字符函数
*/
void RGB_ShowChar(uint8_t x,uint8_t y,uint8_t chr){
  unsigned char c=0,i=0;
  int BCD[8]={};
  c=chr-' ';//得到偏移后的值 //也就是字符对应的 ASCII表 的数字值     
  if(x>kMatrixHeight-1)x=0; //最大32
  if(y>kMatrixWidth-1) y=0;  //最大8
  for(i=0;i<6;i++){
    FONT_16_2(F6x8[c][i],&BCD[0]);
    DebugPrintln();
    for(int j=0;j<8;j++){
      if(BCD[j]==0){
        DebugPrint("   ");
        leds[ RGBXYsafe(x+i, y+7-j)] = CHSV( 0, 255, 0);
      }
      else{
        DebugPrint(" @ ");
        leds[ RGBXYsafe(x+i, y+7-j)] = CHSV( 120, 255, 255);
      }
    }
  }
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.show();
  DebugPrintln();
}

/*
@说明：RGB显示字符串
*/
void RGB_ShowString(uint8_t x,uint8_t y,const char *chr){
  uint8_t j=0;
  while (chr[j]!='\0'){
    RGB_ShowChar(x,y,chr[j]);
      x+=6;
    if(x>32){x=0;y=0;}
      j++;
    delay(1);
    ESP.wdtFeed();// 喂 狗
  }
}

/*
@说明：RGB显示数字
*/
void RGB_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len){
  uint8_t t,tp;
  uint8_t enshow=0;               
  for(t=0;t<len;t++)//每次取一个数字显示
  {
    //转化数组ACIIC 到字符ACIIC 后面加了个'0'
    tp=(num/RGB_POW(10,len-t-1))%10;
    if(enshow==0&&t<(len-1))
    {
      if(tp==0)
      {
        RGB_ShowChar(x+6*t,y,'0');
        continue;
      }else enshow=1;  
    }
    RGB_ShowChar(x+6*t,y,tp+48);//tp+'0'
  }
}

/*
@说明：十六进制转数组
*/
void FONT_16_2(const unsigned char chr,int *point){
   int a=chr;
   *point= a/128;
   a=a-128*(*point);point++;
   *point= a/64;
   a=a-64*(*point);point++;
   *point= a/32;
   a=a-32*(*point);point++;
   *point= a/16;
   a=a-16*(*point);point++;
   *point= a/8;
   a=a-8*(*point);point++;
   *point= a/4;
   a=a-4*(*point);point++;
   *point= a/2;
   a=a-2*(*point);point++;
   *point= a;
}

/*
@说明：RGB  m^n 
*/
int RGB_POW(char m,char n){
  int result = 1;
  while(n--){
    result*=m;
    ESP.wdtFeed();// 喂 狗
  }
  return result;
}

/*
@功能:获取网络时间部分代码
@说明:太复杂，不看~
*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime(void){
  IPAddress ntpServerIP; // NTP server's ip address

  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  // get a random server from the pool
  WiFi.hostByName(ntpServerName, ntpServerIP);
  Serial.print(ntpServerName);
  Serial.print(": ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");//没连接到NTP服务器
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}